package com.geek.factory.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.geek.factory.annotation.BizLogRecord;
import com.geek.factory.constant.SuccessConstant;
import com.geek.factory.entity.StockOut;
import com.geek.factory.entity.StockOutDetail;
import com.geek.factory.entity.InventoryDistribution;
import com.geek.factory.result.Result;
import com.geek.factory.service.IStockOutService;
import com.geek.factory.service.IStockOutDetailService;
import com.geek.factory.service.IInventoryDistributionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 出库单主表控制器
 */
@RestController
@RequestMapping("/stock-out")
@Api(tags = "后台系统的 - 出库单模块")
@Slf4j
@CrossOrigin
public class StockOutController {

    @Autowired
    private IStockOutService stockOutService;

    @Autowired
    private IStockOutDetailService stockOutDetailService;

    @Autowired
    private IInventoryDistributionService inventoryDistributionService;

    /**
     * 生成出库单编号
     */
    private String generateStockOutCode() {
        String prefix = "SO";
        String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String timeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmmss"));
        return prefix + dateStr + timeStr;
    }

    @ApiOperation("通过ID查询出库单信息")
    @GetMapping("/{stockOutId}")
    public Result findStockOutById(@ApiParam("出库单ID") @PathVariable("stockOutId") Integer stockOutId) {
        StockOut stockOut = stockOutService.getById(stockOutId);
        log.info("stockOut: {}", stockOut);
        if (stockOut != null) {
            // 查询明细
            QueryWrapper<StockOutDetail> detailWrapper = new QueryWrapper<>();
            detailWrapper.eq("stock_out_id", stockOutId);
            List<StockOutDetail> details = stockOutDetailService.list(detailWrapper);

            Map<String, Object> result = new HashMap<>();
            result.put("stockOut", stockOut);
            result.put("details", details);

            return new Result(SuccessConstant.SUCCESS, "ok", result);
        }
        return new Result(SuccessConstant.FAIL, "出库单不存在");
    }

    @ApiOperation("新增出库单")
    @PostMapping
    @Transactional
    @BizLogRecord(value = "出库", description = "新增出库单", logParams = true, logResult = true)
    public Result addStockOut(@RequestBody Map<String, Object> request) {
        try {
            // 解析请求数据
            StockOut stockOut = new StockOut();
            stockOut.setStockOutCode(generateStockOutCode());
            stockOut.setWarehouseId((Integer) request.get("warehouseId"));
            stockOut.setOutType((String) request.get("outType"));
            stockOut.setOperator((String) request.get("operator"));
            stockOut.setRemark((String) request.get("remark"));
            stockOut.setCreatedTime(LocalDateTime.now());
            stockOut.setCreatedBy("admin"); // 实际项目中应从登录用户获取

            // 保存出库单
            boolean isSuccess = stockOutService.save(stockOut);
            if (!isSuccess) {
                return new Result(SuccessConstant.FAIL, "保存出库单失败");
            }

            // 保存明细并更新库存
            List<Map<String, Object>> details = (List<Map<String, Object>>) request.get("details");
            if (details != null && !details.isEmpty()) {
                for (Map<String, Object> detailMap : details) {
                    StockOutDetail detail = new StockOutDetail();
                    detail.setStockOutId(stockOut.getStockOutId());
                    detail.setProductId((Integer) detailMap.get("productId"));
                    detail.setMaterialId((Integer) detailMap.get("materialId"));
                    detail.setShelfId((Integer) detailMap.get("shelfId"));
                    detail.setQuantity(new BigDecimal(detailMap.get("quantity").toString()));
                    detail.setUnit((String) detailMap.get("unit"));

                    stockOutDetailService.save(detail);

                    // 更新库存分布（出库减少库存）
                    updateInventoryDistribution(detail, stockOut.getWarehouseId(), "subtract");
                }
            }

            log.info("新增出库单: {}, 结果: {}", stockOut, isSuccess);
            return new Result(SuccessConstant.SUCCESS, "新增成功", stockOut);
        } catch (Exception e) {
            log.error("新增出库单失败", e);
            return new Result(SuccessConstant.FAIL, "新增失败: " + e.getMessage());
        }
    }

    /**
     * 更新库存分布
     */
    private void updateInventoryDistribution(StockOutDetail detail, Integer warehouseId, String operation) {
        try {
            QueryWrapper<InventoryDistribution> wrapper = new QueryWrapper<>();
            wrapper.eq("warehouse_id", warehouseId);
            wrapper.eq("shelf_id", detail.getShelfId());

            if (detail.getProductId() != null) {
                wrapper.eq("product_id", detail.getProductId());
            } else if (detail.getMaterialId() != null) {
                wrapper.eq("material_id", detail.getMaterialId());
            }

            InventoryDistribution inventory = inventoryDistributionService.getOne(wrapper);

            if (inventory == null) {
                log.warn("库存记录不存在，无法出库");
                throw new RuntimeException("指定货柜中库存不足");
            } else {
                // 更新现有库存
                if ("add".equals(operation)) {
                    inventory.setQuantity(inventory.getQuantity().add(detail.getQuantity()));
                } else if ("subtract".equals(operation)) {
                    if (inventory.getQuantity().compareTo(detail.getQuantity()) < 0) {
                        throw new RuntimeException("指定货柜中库存不足");
                    }
                    inventory.setQuantity(inventory.getQuantity().subtract(detail.getQuantity()));
                }
                inventory.setUpdatedTime(LocalDateTime.now());
                inventory.setUpdatedBy("admin");
                inventoryDistributionService.updateById(inventory);
            }
        } catch (Exception e) {
            log.error("更新库存分布失败", e);
            throw e;
        }
    }

    @ApiOperation("根据ID删除出库单")
    @DeleteMapping("/{stockOutId}")
    @Transactional
    @BizLogRecord(value = "出库", description = "删除出库单", logParams = true, logResult = true)
    public Result deleteStockOut(@ApiParam("出库单ID") @PathVariable("stockOutId") Integer stockOutId) {
        try {
            // 先查询明细，用于恢复库存
            QueryWrapper<StockOutDetail> detailWrapper = new QueryWrapper<>();
            detailWrapper.eq("stock_out_id", stockOutId);
            List<StockOutDetail> details = stockOutDetailService.list(detailWrapper);

            StockOut stockOut = stockOutService.getById(stockOutId);

            // 恢复库存（出库单删除时增加库存）
            for (StockOutDetail detail : details) {
                updateInventoryDistribution(detail, stockOut.getWarehouseId(), "add");
            }

            // 删除明细
            stockOutDetailService.remove(detailWrapper);

            // 删除出库单
            boolean isSuccess = stockOutService.removeById(stockOutId);
            log.info("删除出库单ID: {}, 结果: {}", stockOutId, isSuccess);
            if (isSuccess) {
                return new Result(SuccessConstant.SUCCESS, "删除成功");
            }
            return new Result(SuccessConstant.FAIL, "删除失败");
        } catch (Exception e) {
            log.error("删除出库单失败", e);
            return new Result(SuccessConstant.FAIL, "删除失败: " + e.getMessage());
        }
    }

    @ApiOperation("修改出库单信息")
    @PutMapping("/{stockOutId}")
    @Transactional
    @BizLogRecord(value = "出库", description = "修改出库单", logParams = true, logResult = true)
    public Result updateStockOut(@ApiParam("出库单ID") @PathVariable("stockOutId") Integer stockOutId, @RequestBody Map<String, Object> request) {
        try {
            StockOut stockOut = new StockOut();
            stockOut.setStockOutId(stockOutId);
            stockOut.setWarehouseId((Integer) request.get("warehouseId"));
            stockOut.setOutType((String) request.get("outType"));
            stockOut.setOperator((String) request.get("operator"));
            stockOut.setRemark((String) request.get("remark"));

            boolean isSuccess = stockOutService.updateById(stockOut);
            log.info("修改出库单: {}, 结果: {}", stockOut, isSuccess);
            if (isSuccess) {
                return new Result(SuccessConstant.SUCCESS, "修改成功", stockOut);
            }
            return new Result(SuccessConstant.FAIL, "修改失败");
        } catch (Exception e) {
            log.error("修改出库单失败", e);
            return new Result(SuccessConstant.FAIL, "修改失败: " + e.getMessage());
        }
    }

    @ApiOperation("分页查询出库单列表")
    @GetMapping("/page")
    public Result getStockOutPage(
            @RequestParam(defaultValue = "1") Integer current,
            @RequestParam(defaultValue = "10") Integer size,
            @RequestParam(required = false) String stockOutCode,
            @RequestParam(required = false) String outType
    ) {
        QueryWrapper<StockOut> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(stockOutCode)) {
            wrapper.like("stock_out_code", stockOutCode);
        }
        if (StringUtils.isNotBlank(outType)) {
            wrapper.eq("out_type", outType);
        }
        wrapper.orderByDesc("created_time");

        Page<StockOut> page = stockOutService.page(new Page<>(current, size), wrapper);
        Map<String, Object> data = new HashMap<>();
        data.put("records", page.getRecords());
        data.put("total", page.getTotal());
        data.put("current", page.getCurrent());
        data.put("size", page.getSize());
        data.put("pages", page.getPages());

        return new Result(SuccessConstant.SUCCESS, "查询成功", data);
    }

    @ApiOperation("获取所有出库单列表")
    @GetMapping("/list")
    public Result getAllStockOuts() {
        List<StockOut> stockOuts = stockOutService.list();
        return new Result(SuccessConstant.SUCCESS, "查询成功", stockOuts);
    }
}